//
// Created on 2025/8/23.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include "md_renderer.h"
#include "md_log.h"
#include "md_defines.h"
#include "device/md_egl.h"
#include "device/md_nativeimage_ref.h"
#include "md_object_3d.h"
#include <unistd.h>
#include <thread>
#include <GLES3/gl3.h>
#include <GLES2/gl2ext.h>

#include <mutex>

namespace asha {
namespace vrlib {

const char* VERTEX_SHADER = R"(
    attribute vec4 a_Position;
    attribute vec2 a_TexCoordinate;
    uniform mat4 u_MVPMatrix;
    uniform mat4 u_STMatrix;
    varying vec2 v_TexCoordinate;
    void main() {
        v_TexCoordinate = (u_STMatrix * vec4(a_TexCoordinate, 0, 1)).xy;
        gl_Position = u_MVPMatrix * a_Position;
    }
)";

const char* FRAGMENT_SHADER = R"(
    #extension GL_OES_EGL_image_external : require
    precision mediump float;
    uniform samplerExternalOES u_Texture;
    varying vec2 v_TexCoordinate;
    void main() {
        gl_FragColor = texture2D(u_Texture, v_TexCoordinate);
    }
)";

class MD360RendererPrivate : public MD360RendererAPI, public std::enable_shared_from_this<MD360RendererPrivate> {
public:
    virtual int SetSurface(std::shared_ptr<MDNativeWindowRef> ref) override {
        return egl_->SetRenderWindow(ref);
    }
    
    virtual void UpdateMVPMatrix(float* matrix) override {
        std::lock_guard<std::mutex> lock(mutex_);
        if (matrix) {
            std::copy(matrix, matrix + 16, current_mvp_matrix_);
        }
    }
    
    virtual uint64_t GetVideoSurfaceId() override {
        return surface_id_;
    }

    virtual void SetClearColor(float r, float g, float b, float a) override {
        std::lock_guard<std::mutex> lock(mutex_);
        MD_LOGI("MD360RendererPrivate::SetClearColor called: r=%.3f, g=%.3f, b=%.3f, a=%.3f", r, g, b, a);
        clear_color_[0] = r;
        clear_color_[1] = g;
        clear_color_[2] = b;
        clear_color_[3] = a;
    }

    virtual void SetCullFaceEnabled(bool enabled) override {
        std::lock_guard<std::mutex> lock(mutex_);
        MD_LOGI("MD360RendererPrivate::SetCullFaceEnabled called: enabled=%s", enabled ? "true" : "false");
        cull_face_enabled_ = enabled;
        // 状态会在 OnDrawFrame 中应用
    }

    virtual void SetDepthTestEnabled(bool enabled) override {
        std::lock_guard<std::mutex> lock(mutex_);
        MD_LOGI("MD360RendererPrivate::SetDepthTestEnabled called: enabled=%s", enabled ? "true" : "false");
        depth_test_enabled_ = enabled;
        // 状态会在 OnDrawFrame 中应用
    }

    virtual int OnDrawFrame() override {
        {
            std::lock_guard<std::mutex> lock(mutex_);
            glClearColor(clear_color_[0], clear_color_[1], clear_color_[2], clear_color_[3]);
            
            // 应用渲染状态
            if (cull_face_enabled_) {
                glEnable(GL_CULL_FACE);
            } else {
                glDisable(GL_CULL_FACE);
            }
            
            if (depth_test_enabled_) {
                glEnable(GL_DEPTH_TEST);
            } else {
                glDisable(GL_DEPTH_TEST);
            }
        }
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        if (program_ == 0) return MD_ERR;

        glUseProgram(program_);
        
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
        glUniform1i(u_texture_loc_, 0);
        
        float mvp[16];
        {
            std::lock_guard<std::mutex> lock(mutex_);
            std::copy(current_mvp_matrix_, current_mvp_matrix_ + 16, mvp);
        }
        
        glUniformMatrix4fv(u_mvp_matrix_loc_, 1, GL_FALSE, mvp);
        
        glUniformMatrix4fv(u_st_matrix_loc_, 1, GL_FALSE, st_matrix_);
        
        if (object3d_) {
            object3d_->Draw();
        }
        
        return MD_OK;
    }

    //// MD360LifecycleAPI
    virtual int Init() override {
        if (is_init_) {
            return MD_OK;
        }
        is_init_ = true;
        std::weak_ptr<MD360RendererPrivate> weak_this = shared_from_this();
        thread_ = std::thread([=]() {
            auto shared_this = weak_this.lock();
            if (shared_this == nullptr) {
                return;
            }
            shared_this->RunGL();
            MD_LOGI("MD360RendererPrivate gl thread exit ok.");
        });
        return MD_OK;
    }
    virtual int Destroy() override {
        if (is_destroyed_) {
            return MD_OK;
        }
        is_destroyed_ = true;
        MD_LOGI("MD360RendererPrivate::Destroy");
        
        // 等待渲染线程退出
        if (thread_.joinable()) {
            thread_.join();
            MD_LOGI("MD360RendererPrivate::Destroy thread joined");
        }
        
        return MD_OK;
    }
    virtual int Resume() override {
        is_paused_ = false;
        return MD_OK;
    }
    virtual int Pause() override {
        is_paused_ = true;
        return MD_OK;
    }
private:
    int OnSurfaceIdChanged(uint64_t surface_id) {
        // Notify ArkTS about the surfaceId (via callback or event, but here we just log)
        MD_LOGI("OnSurfaceIdChanged: %llu", surface_id);
        return MD_OK;
    }

    GLuint LoadShader(GLenum type, const char* shaderSrc) {
        GLuint shader = glCreateShader(type);
        glShaderSource(shader, 1, &shaderSrc, nullptr);
        glCompileShader(shader);
        GLint compiled;
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
        if (!compiled) {
            GLint infoLen = 0;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen > 1) {
                char* infoLog = new char[infoLen];
                glGetShaderInfoLog(shader, infoLen, nullptr, infoLog);
                MD_LOGE("Error compiling shader: %s", infoLog);
                delete[] infoLog;
            }
            glDeleteShader(shader);
            return 0;
        }
        return shader;
    }

    void InitShaders() {
        GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, VERTEX_SHADER);
        GLuint fragmentShader = LoadShader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER);
        
        program_ = glCreateProgram();
        glAttachShader(program_, vertexShader);
        glAttachShader(program_, fragmentShader);
        
        // Bind attributes before linking
        glBindAttribLocation(program_, 0, "a_Position");
        glBindAttribLocation(program_, 1, "a_TexCoordinate");
        
        glLinkProgram(program_);
        
        GLint linked;
        glGetProgramiv(program_, GL_LINK_STATUS, &linked);
        if (!linked) {
            MD_LOGE("Error linking program");
            glDeleteProgram(program_);
            program_ = 0;
            return;
        }
        
        u_mvp_matrix_loc_ = glGetUniformLocation(program_, "u_MVPMatrix");
        u_texture_loc_ = glGetUniformLocation(program_, "u_Texture");
        u_st_matrix_loc_ = glGetUniformLocation(program_, "u_STMatrix");
        
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
    }

    int RunGL() {
        if (is_destroyed_) {
            return MD_OK;
        }
        int ret = egl_->Prepare();
        if (ret != MD_OK) {
            MD_LOGE("egl_->Prepare failed");
        }
        ret = egl_->MakeCurrent(true);
        if (ret != MD_OK) {
            MD_LOGE("egl_->MakeCurrent failed");
        }
        
        // Init GL resources
        InitShaders();
        object3d_ = std::make_shared<MDObject3D>();
        object3d_->LoadSphere();
        
        // 初始化渲染状态（默认启用）
        {
            std::lock_guard<std::mutex> lock(mutex_);
            MD_LOGI("MD360RendererPrivate::RunGL initializing render states: GL_CULL_FACE=ON, GL_DEPTH_TEST=ON");
            glEnable(GL_CULL_FACE);
            glEnable(GL_DEPTH_TEST);
            cull_face_enabled_ = true;
            depth_test_enabled_ = true;
        }
        
        glGenTextures(1, &texture_id_);
        
        // 创建一个测试纹理（纯色纹理，用于测试渲染）
        // 注意：当前主要使用视频纹理（NativeImage），但如果没有视频源，可以创建一个测试纹理
        // 这里我们仍然创建 NativeImage，但会在 UpdateSurface 中使用单位矩阵
        std::shared_ptr<MDNativeImageRef> native_image_ref = std::make_shared<MDNativeImageRef>(texture_id_);
        surface_id_ = native_image_ref->GetSurfaceId();
        OnSurfaceIdChanged(surface_id_);
        
        // 可选：创建一个简单的测试纹理（2D 纹理，用于位图）
        // 如果将来需要支持位图纹理，可以在这里创建
        // GLuint test_texture_id;
        // glGenTextures(1, &test_texture_id);
        // glBindTexture(GL_TEXTURE_2D, test_texture_id);
        // // 创建一个 1x1 的纯色纹理（红色，用于测试）
        // unsigned char test_pixel[4] = {255, 0, 0, 255}; // RGBA: 红色
        // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, test_pixel);
        // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        
        while (!is_destroyed_) {
            ret = egl_->Prepare();
            if (ret != MD_OK) {
                MD_LOGE("egl_->Prepare failed");
                break;
            }
            
            if (!is_paused_) {
                egl_->MakeCurrent(true);
                // MD_LOGI("OnDrawFrame");
                native_image_ref->UpdateSurface(st_matrix_);
                OnDrawFrame();
                egl_->SwapBuffer();
                egl_->MakeCurrent(false);
            }
            usleep(17 * 1000);
        }
        
        if (object3d_) {
            object3d_->Destroy();
            object3d_ = nullptr;
        }
        if (program_ != 0) {
            glDeleteProgram(program_);
            program_ = 0;
        }
        
        OnSurfaceIdChanged(0);
        egl_->Terminate();
        return MD_OK;
    }
private:
    bool is_init_ = false;
    bool is_destroyed_ = false;
    bool is_paused_ = false;
    uint64_t surface_id_ = 0;
    GLuint texture_id_ = 0;
    std::thread thread_;
    std::shared_ptr<MDEgl> egl_ = MDEgl::CreateEgl();
    
    std::shared_ptr<MDObject3D> object3d_;
    GLuint program_ = 0;
    GLint u_mvp_matrix_loc_ = -1;
    GLint u_texture_loc_ = -1;
    GLint u_st_matrix_loc_ = -1;
    // 初始化 ST 矩阵为单位矩阵
    float st_matrix_[16] = {
        1.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f
    };
    
    std::mutex mutex_;
    float current_mvp_matrix_[16] = {
        1,0,0,0, 
        0,1,0,0, 
        0,0,1,0, 
        0,0,0,1
    };
    float clear_color_[4] = {0.0f, 0.0f, 0.0f, 1.0f}; // RGBA: 默认黑色
    bool cull_face_enabled_ = true;  // 默认启用面剔除
    bool depth_test_enabled_ = true; // 默认启用深度测试
};

std::shared_ptr<MD360RendererAPI> MD360RendererAPI::CreateRenderer() {
    auto renderer = std::make_shared<MD360RendererPrivate>();
    return renderer;
} 


}
};

